/*
* Created by Harm for TeknoParrot
* This file is part of the OpenParrot project - https://teknoparrot.com / https://github.com/teknogods
*
* See LICENSE and MENTIONS in the root of the source tree for information
* regarding licensing.
*/

extern "C" {
	#include "OpenSndVoyager.h"
}
#include <vector>
#include <xaudio2.h>
#pragma comment(lib, "xaudio2.lib")
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")

#ifdef _DEBUG
void info(const char* format, ...)
{
	va_list args;
	char buffer[1024];

	va_start(args, format);
	int len = _vsnprintf_s(buffer, sizeof(buffer), format, args);
	va_end(args);

	buffer[len] = '\n';
	buffer[len + 1] = '\0';

	OutputDebugStringA(buffer);
}
#else
#define info(x, ...) {}
#endif


struct qSample
{
	WORD sample;
	BYTE speed;
	BYTE level;
	WORD stay;
	qSample(WORD sample, BYTE speed, BYTE level, WORD stay) : sample(sample), speed(speed), level(level), stay(stay) {}
};

struct BUFFER
{
	WAVEFORMATEX xaFormat;
	XAUDIO2_BUFFER xaBuffer;
	IXAudio2SourceVoice* xaVoice;
	XA2Callback xaCallback;
	BOOL playing;
	BOOL loop;
	std::vector<qSample> qSamples;
	SHORT qIndex;
};

// Buffers
BUFFER channelBuffer[CHANNELS];
//SAMPLE sampleBuffer[SAMPLES];
DWORD hexSize = 0x12E08;
BYTE* pHexBuffer = new BYTE[hexSize];

DWORD sampleHeadersSize = 0x6DD0;
BYTE* pSampleHeaders = new BYTE[sampleHeadersSize];

// Xaudio2
IXAudio2* pXAudio2 = NULL;
IXAudio2MasteringVoice* pMasterVoice = NULL;
BYTE* pDataBuffer = NULL;
DWORD binSize = 0x100000;
DWORD bufferSize = binSize * 4;
BOOL bufferReady = FALSE;
DWORD sampleCount = 0;

float restMultiplier = 4.4f;

void XA2Callback::OnBufferEnd(void* cxt)
{
	info("OnBufferEnd channel: %u qIndex: %d qSamples size: %d", channel, channelBuffer[channel].qIndex, channelBuffer[channel].qSamples.size());

	if (!channelBuffer[channel].playing)
		StopChannel(channel);

	if (channelBuffer[channel].qIndex < channelBuffer[channel].qSamples.size() - 1)
	{
		PlayChannelNext(channel);
	}
	else
	{
		channelBuffer[channel].playing = FALSE;
	}
}

const BYTE blob[4256] = { 0x83, 0xF3, 0x00, 0x00, 0xB9, 0xFF, 0x00, 0x00, 0xA7, 0xFF, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xB2, 0x8F, 0x00, 0x00, 0xE1, 0xB7, 0x00, 0x00, 0x79, 0xB7, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xBE, 0xE8, 0x00, 0x00, 0xA9, 0xFB, 0x00, 0x00, 0x80, 0xF9, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x64, 0x00, 0x00, 0x18, 0x62, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x78, 0x00, 0x00, 0xF4, 0x46, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xD2, 0xEC, 0x00, 0x00, 0xF5, 0xFF, 0x00, 0x00, 0xF1, 0xFF, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x40, 0x74, 0x00, 0x00, 0xC9, 0xBF, 0x00, 0x00, 0x40, 0xBF, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xDF, 0xC0, 0x00, 0x00, 0xC4, 0xDD, 0x00, 0x00, 0x0A, 0xDC, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x54, 0x00, 0x00, 0x3D, 0x54, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xB2, 0xF1, 0x00, 0x00, 0x12, 0xFD, 0x00, 0x00, 0xFE, 0xFC, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x73, 0xCC, 0x00, 0x00, 0xB1, 0xF1, 0x00, 0x00, 0xA1, 0xF1, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0xCA, 0x00, 0x00, 0xF7, 0xEE, 0x00, 0x00, 0xF0, 0xEE, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x1E, 0x58, 0x00, 0x00, 0xCE, 0x93, 0x00, 0x00, 0x5F, 0x92, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x40, 0xCE, 0x00, 0x00, 0x54, 0xF4, 0x00, 0x00, 0x4C, 0xF4, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x9B, 0xB7, 0x00, 0x00, 0x94, 0xED, 0x00, 0x00, 0x62, 0xED, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x4A, 0xEE, 0x00, 0x00, 0xEE, 0xFA, 0x00, 0x00, 0xE8, 0xFA, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x36, 0xEC, 0x00, 0x00, 0x2E, 0xFF, 0x00, 0x00, 0x29, 0xFF, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xBC, 0x9B, 0x00, 0x00, 0x63, 0xC8, 0x00, 0x00, 0xF8, 0xC2, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xFA, 0xEE, 0x00, 0x00, 0x26, 0xF8, 0x00, 0x00, 0x21, 0xF8, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x71, 0xCF, 0x00, 0x00, 0x84, 0xF0, 0x00, 0x00, 0x47, 0xF0, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x16, 0xC6, 0x00, 0x00, 0x44, 0xE4, 0x00, 0x00, 0xF2, 0xE3, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x7E, 0xC3, 0x00, 0x00, 0x2E, 0xFE, 0x00, 0x00, 0x7D, 0xEC, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5B, 0x7C, 0x00, 0x00, 0x0D, 0x41, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xC3, 0xDB, 0x00, 0x00, 0x4A, 0xFE, 0x00, 0x00, 0x36, 0xFE, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x34, 0xD9, 0x00, 0x00, 0x8C, 0xF2, 0x00, 0x00, 0x4A, 0xF1, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xD8, 0x5B, 0x00, 0x00, 0x9E, 0x98, 0x00, 0x00, 0x4C, 0x98, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0x5E, 0x00, 0x00, 0xEC, 0x5C, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x7E, 0x00, 0x00, 0x64, 0x49, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x7E, 0x00, 0x00, 0x36, 0x52, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x78, 0x00, 0x00, 0xA2, 0xC7, 0x00, 0x00, 0x8B, 0xC7, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x79, 0x00, 0x00, 0xDA, 0x79, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x65, 0xCC, 0x00, 0x00, 0xCF, 0xEC, 0x00, 0x00, 0xA5, 0xEA, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0xC0, 0xD0, 0x00, 0x00, 0x0C, 0xF7, 0x00, 0x00, 0xC8, 0xF4, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xA7, 0x00, 0x00, 0x14, 0xDB, 0x00, 0x00, 0xD0, 0xD8, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x1A, 0x99, 0x00, 0x00, 0x38, 0x97, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0xD4, 0x5B, 0x00, 0x00, 0x93, 0x98, 0x00, 0x00, 0x86, 0x98, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x74, 0x5E, 0x00, 0x00, 0xB2, 0x9C, 0x00, 0x00, 0x44, 0x9B, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xB4, 0x77, 0x00, 0x00, 0x25, 0xC6, 0x00, 0x00, 0x6A, 0xC5, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xA5, 0x98, 0x00, 0x00, 0x1F, 0xC4, 0x00, 0x00, 0x0F, 0xC4, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xA4, 0x5C, 0x00, 0x00, 0x0D, 0x9A, 0x00, 0x00, 0xA5, 0x5C, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0x5B, 0x00, 0x00, 0x9E, 0x5B, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x8F, 0xEC, 0x00, 0x00, 0xCE, 0xFE, 0x00, 0x00, 0xAA, 0xFE, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x3E, 0xEE, 0x00, 0x00, 0xB5, 0xF6, 0x00, 0x00, 0xB4, 0xF6, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xF4, 0xF3, 0x00, 0x00, 0x0C, 0xF8, 0x00, 0x00, 0xFC, 0xF7, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x62, 0x00, 0x00, 0xCE, 0x61, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x75, 0x00, 0x00, 0x0C, 0x75, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x71, 0x00, 0x00, 0x8D, 0x71, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0xE6, 0xB8, 0x00, 0x00, 0x15, 0xD5, 0x00, 0x00, 0xE6, 0xB8, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xE7, 0x7A, 0x00, 0x00, 0xFE, 0xCA, 0x00, 0x00, 0xE4, 0xCA, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x5B, 0x00, 0x00, 0xEC, 0x5B, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x40, 0xD3, 0x00, 0x00, 0x71, 0xF4, 0x00, 0x00, 0x40, 0xF4, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0xD3, 0xBC, 0x00, 0x00, 0x33, 0xD9, 0x00, 0x00, 0xF3, 0xD8, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xB3, 0x9C, 0x00, 0x00, 0x4F, 0xCB, 0x00, 0x00, 0xF3, 0xCA, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x95, 0xA9, 0x00, 0x00, 0x50, 0xA9, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x15, 0xC7, 0x00, 0x00, 0x17, 0xE6, 0x00, 0x00, 0xF5, 0xE5, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x0B, 0xEB, 0x00, 0x00, 0xBB, 0xFC, 0x00, 0x00, 0xB6, 0xFC, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xD4, 0xB9, 0x00, 0x00, 0x16, 0xF0, 0x00, 0x00, 0x0D, 0xF0, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x40, 0x5F, 0x00, 0x00, 0xC2, 0x9D, 0x00, 0x00, 0x60, 0x9D, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x54, 0x00, 0x00, 0xA7, 0x53, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x5B, 0x00, 0x00, 0x2A, 0x5B, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x4B, 0x62, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0xF0, 0xA0, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x80, 0x59, 0x00, 0x00, 0xFF, 0x95, 0x00, 0x00, 0xAF, 0x95, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x7A, 0x00, 0x00, 0x40, 0x79, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x65, 0x00, 0x00, 0xE8, 0x64, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xE4, 0x5B, 0x00, 0x00, 0xC6, 0x98, 0x00, 0x00, 0xAA, 0x98, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x77, 0x00, 0x00, 0x1C, 0x77, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB3, 0x77, 0x00, 0x00, 0x40, 0x77, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x6E, 0x00, 0x00, 0xF5, 0x6D, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x48, 0x94, 0x00, 0x00, 0x04, 0xBE, 0x00, 0x00, 0xFB, 0xBD, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0xBF, 0xAF, 0x00, 0x00, 0x34, 0xE5, 0x00, 0x00, 0xE2, 0xE4, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x91, 0xA8, 0x00, 0x00, 0xC2, 0xDB, 0x00, 0x00, 0x6E, 0xDB, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x9B, 0x72, 0x00, 0x00, 0x66, 0xBC, 0x00, 0x00, 0x5E, 0xBC, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x91, 0xA9, 0x00, 0x00, 0xFA, 0xA8, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xDA, 0xBA, 0x00, 0x00, 0xF0, 0xF1, 0x00, 0x00, 0xD3, 0xF1, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x72, 0x00, 0x00, 0x44, 0x72, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x95, 0x5D, 0x00, 0x00, 0xBC, 0x9B, 0x00, 0x00, 0xB9, 0x9B, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xDB, 0xE7, 0x00, 0x00, 0x7C, 0xFF, 0x00, 0x00, 0xDC, 0xE7, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xE2, 0x5F, 0x00, 0x00, 0x81, 0x9E, 0x00, 0x00, 0x80, 0x9E, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x9B, 0xD7, 0x00, 0x00, 0x0E, 0xFA, 0x00, 0x00, 0x0A, 0xFA, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xCF, 0xD3, 0x00, 0x00, 0x3F, 0xF6, 0x00, 0x00, 0x3B, 0xF6, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x16, 0xDB, 0x00, 0x00, 0x96, 0xFD, 0x00, 0x00, 0x91, 0xFD, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xEA, 0xD7, 0x00, 0x00, 0x5D, 0xFA, 0x00, 0x00, 0x58, 0xFA, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x80, 0x7B, 0x00, 0x00, 0x73, 0xCC, 0x00, 0x00, 0x18, 0xCB, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x98, 0xD1, 0x00, 0x00, 0x1C, 0xF8, 0x00, 0x00, 0x9D, 0xD1, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA8, 0xD3, 0x00, 0x00, 0xFF, 0xFA, 0x00, 0x00, 0xAC, 0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xC6, 0x00, 0x00, 0x08, 0xEB, 0x00, 0x00, 0xED, 0xC6, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xB4, 0xE1, 0x00, 0x00, 0xED, 0xFC, 0x00, 0x00, 0xE4, 0xFC, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xDF, 0x6D, 0x00, 0x00, 0xBE, 0xAF, 0x00, 0x00, 0x81, 0xAF, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x65, 0x00, 0x00, 0xE0, 0x64, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x14, 0x5E, 0x00, 0x00, 0x48, 0x9C, 0x00, 0x00, 0x2E, 0x9C, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x31, 0x9A, 0x00, 0x00, 0x14, 0xC7, 0x00, 0x00, 0x09, 0xC7, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x78, 0x00, 0x00, 0x70, 0x78, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xA7, 0xC4, 0x00, 0x00, 0x7A, 0xFF, 0x00, 0x00, 0x63, 0xFF, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB7, 0x74, 0x00, 0x00, 0xA7, 0x74, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x81, 0x9E, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0xE8, 0xCF, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x8C, 0x62, 0x00, 0x00, 0x75, 0xA1, 0x00, 0x00, 0x32, 0xA1, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x9F, 0x65, 0x00, 0x00, 0xFE, 0xA4, 0x00, 0x00, 0xFC, 0xA4, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x25, 0x68, 0x00, 0x00, 0xFC, 0xA7, 0x00, 0x00, 0xF7, 0xA7, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xE4, 0xF5, 0x00, 0x00, 0x98, 0xFC, 0x00, 0x00, 0x95, 0xFC, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x71, 0x00, 0x00, 0xFB, 0x71, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x58, 0x00, 0x00, 0x08, 0x58, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x7A, 0x00, 0x00, 0xBD, 0xC9, 0x00, 0x00, 0x39, 0xC9, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x80, 0x71, 0x00, 0x00, 0x1F, 0xB7, 0x00, 0x00, 0xA0, 0xB6, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xE6, 0xEC, 0x00, 0x00, 0x18, 0xFC, 0x00, 0x00, 0x15, 0xFC, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x70, 0xEE, 0x00, 0x00, 0xE7, 0xFC, 0x00, 0x00, 0xDF, 0xFC, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x16, 0xCC, 0x00, 0x00, 0x36, 0xEC, 0x00, 0x00, 0xF6, 0xEB, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x13, 0x7C, 0x00, 0x00, 0x73, 0xCD, 0x00, 0x00, 0x68, 0xCD, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5F, 0x00, 0x00, 0x13, 0x5F, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x05, 0xBE, 0x00, 0x00, 0x84, 0xDA, 0x00, 0x00, 0x6D, 0xDA, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x26, 0xC6, 0x00, 0x00, 0x86, 0xE9, 0x00, 0x00, 0x46, 0xE9, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x44, 0xF5, 0x00, 0x00, 0xB3, 0xFA, 0x00, 0x00, 0xB0, 0xFA, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xA3, 0xE2, 0x00, 0x00, 0xF0, 0xFD, 0x00, 0x00, 0xDE, 0xFD, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x7C, 0x00, 0x00, 0x39, 0x7C, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x75, 0x00, 0x00, 0x40, 0x75, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x82, 0xBD, 0x00, 0x00, 0x43, 0xF5, 0x00, 0x00, 0x82, 0xBD, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xD1, 0x7F, 0x00, 0x00, 0xA2, 0xD3, 0x00, 0x00, 0xBE, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA9, 0x6F, 0x00, 0x00, 0x48, 0xB4, 0x00, 0x00, 0x05, 0xB4, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x5C, 0x7C, 0x00, 0x00, 0x81, 0xCE, 0x00, 0x00, 0xFD, 0xCD, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x8D, 0xF2, 0x00, 0x00, 0x92, 0xFF, 0x00, 0x00, 0x7C, 0xFF, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x5E, 0x00, 0x00, 0xF8, 0x5C, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0xF7, 0xB2, 0x00, 0x00, 0x90, 0xE8, 0x00, 0x00, 0x24, 0xE8, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xA7, 0x9D, 0x00, 0x00, 0x89, 0xCD, 0x00, 0x00, 0x55, 0xCD, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA9, 0x6F, 0x00, 0x00, 0xE4, 0x6E, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x58, 0x00, 0x00, 0x2C, 0x58, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0x72, 0x00, 0x00, 0xCA, 0x72, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x5B, 0x00, 0x00, 0xB4, 0x5B, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0xCF, 0xF7, 0x00, 0x00, 0x21, 0xFF, 0x00, 0x00, 0x17, 0xFF, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xB0, 0x68, 0x00, 0x00, 0x91, 0xA8, 0x00, 0x00, 0x2C, 0xA8, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x40, 0x7A, 0x00, 0x00, 0x40, 0xCA, 0x00, 0x00, 0x3C, 0xCA, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xFE, 0xA4, 0x00, 0x00, 0x9B, 0xD7, 0x00, 0x00, 0x98, 0xD7, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x68, 0x00, 0x00, 0x22, 0x68, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xCA, 0xBF, 0x00, 0x00, 0xCF, 0xF7, 0x00, 0x00, 0xCC, 0xF7, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x96, 0xA9, 0x00, 0x00, 0x8B, 0xDD, 0x00, 0x00, 0x88, 0xDD, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7A, 0x6E, 0x00, 0x00, 0x77, 0x6E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x68, 0x00, 0x00, 0xAD, 0x68, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xC2, 0x5F, 0x00, 0x00, 0x4E, 0x9E, 0x00, 0x00, 0x4B, 0x9E, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6D, 0x00, 0x00, 0x74, 0x6D, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xC9, 0x65, 0x00, 0x00, 0x4D, 0xA5, 0x00, 0x00, 0x4A, 0xA5, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xF6, 0xE9, 0x00, 0x00, 0x91, 0xFE, 0x00, 0x00, 0x8E, 0xFE, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x77, 0x00, 0x00, 0x7B, 0x77, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x72, 0x00, 0x00, 0x98, 0x72, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xC3, 0x9D, 0x00, 0x00, 0xCC, 0xCD, 0x00, 0x00, 0xC9, 0xCD, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0xAC, 0x71, 0x00, 0x00, 0x9B, 0xB7, 0x00, 0x00, 0x98, 0xB7, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x87, 0xCF, 0x00, 0x00, 0xCE, 0xF5, 0x00, 0x00, 0xCB, 0xF5, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xAB, 0xC7, 0x00, 0x00, 0x1E, 0xEC, 0x00, 0x00, 0x0D, 0xEC, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x40, 0x54, 0x00, 0x00, 0xB1, 0x8F, 0x00, 0x00, 0xA3, 0x8F, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xDD, 0xC5, 0x00, 0x00, 0xA6, 0xE8, 0x00, 0x00, 0xA0, 0xE8, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xFF, 0xCA, 0x00, 0x00, 0xFE, 0xEF, 0x00, 0x00, 0xE0, 0xEF, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, 0xE3, 0x00, 0x00, 0x76, 0xFE, 0x00, 0x00, 0x5B, 0xFE, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x17, 0x90, 0x00, 0x00, 0xE5, 0xB8, 0x00, 0x00, 0xB6, 0xB8, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x8A, 0xF0, 0x00, 0x00, 0x72, 0xFF, 0x00, 0x00, 0x71, 0xFF, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x89, 0xCD, 0x00, 0x00, 0x70, 0xEE, 0x00, 0x00, 0x45, 0xEE, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x15, 0xD5, 0x00, 0x00, 0x4A, 0xEE, 0x00, 0x00, 0x1C, 0xEE, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x5F, 0xD1, 0x00, 0x00, 0xE3, 0xF7, 0x00, 0x00, 0xBE, 0xF7, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xCC, 0xCD, 0x00, 0x00, 0xBB, 0xEE, 0x00, 0x00, 0x95, 0xEE, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x4D, 0xA5, 0x00, 0x00, 0xE9, 0xD7, 0x00, 0x00, 0xE6, 0xD7, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xE0, 0xEA, 0x00, 0x00, 0xD5, 0xFD, 0x00, 0x00, 0xD4, 0xFD, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xBB, 0xEE, 0x00, 0x00, 0x3F, 0xFD, 0x00, 0x00, 0x33, 0xFD, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x73, 0xCD, 0x00, 0x00, 0x83, 0xF3, 0x00, 0x00, 0x61, 0xF3, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xEC, 0xD3, 0x00, 0x00, 0x8F, 0xEC, 0x00, 0x00, 0x8E, 0xEC, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xFF, 0x95, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x1E, 0xC0, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x49, 0x9C, 0x00, 0x00, 0x4E, 0xC9, 0x00, 0x00, 0x09, 0xC9, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x54, 0x9D, 0x00, 0x00, 0x64, 0xCC, 0x00, 0x00, 0x14, 0xCC, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x77, 0x6D, 0x00, 0x00, 0xA8, 0xAE, 0x00, 0x00, 0x98, 0xAE, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xD6, 0x72, 0x00, 0x00, 0xE2, 0xBD, 0x00, 0x00, 0xCA, 0xBD, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x4F, 0xC9, 0x00, 0x00, 0xBD, 0xE8, 0x00, 0x00, 0xA8, 0xE8, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x84, 0xDA, 0x00, 0x00, 0x53, 0xF4, 0x00, 0x00, 0x33, 0xF4, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x90, 0xE8, 0x00, 0x00, 0xBE, 0xFB, 0x00, 0x00, 0xA7, 0xFB, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xF1, 0xC2, 0x00, 0x00, 0xDC, 0xDF, 0x00, 0x00, 0xC0, 0xDF, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x05, 0xE4, 0x00, 0x00, 0xF4, 0xFF, 0x00, 0x00, 0xDC, 0xFF, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x8B, 0xDD, 0x00, 0x00, 0x2D, 0xF9, 0x00, 0x00, 0x1A, 0xF9, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0xFF, 0xEF, 0x00, 0x00, 0xD2, 0xF9, 0x00, 0x00, 0xCA, 0xF9, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1F, 0xEC, 0x00, 0x00, 0x1E, 0xFE, 0x00, 0x00, 0x0E, 0xFE, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x7A, 0x6E, 0x00, 0x00, 0xD0, 0xB1, 0x00, 0x00, 0xFA, 0xB0, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x4F, 0xE7, 0x00, 0x00, 0xE2, 0xFF, 0x00, 0x00, 0x9F, 0xFF, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x90, 0x58, 0x00, 0x00, 0x48, 0x94, 0x00, 0x00, 0xD0, 0x93, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0xB2, 0xAE, 0x00, 0x00, 0x05, 0xE4, 0x00, 0x00, 0xD4, 0xE3, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x87, 0x6E, 0x00, 0x00, 0xF7, 0xB2, 0x00, 0x00, 0xF4, 0xB2, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xC7, 0xDD, 0x00, 0x00, 0x94, 0xF8, 0x00, 0x00, 0x91, 0xF8, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0xE4, 0x5B, 0x00, 0x00, 0xF6, 0x98, 0x00, 0x00, 0xF3, 0x98, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x67, 0xBC, 0x00, 0x00, 0xF4, 0xF3, 0x00, 0x00, 0xF1, 0xF3, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x16, 0x72, 0x00, 0x00, 0xD4, 0xB9, 0x00, 0x00, 0xBD, 0xB9, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x7C, 0x00, 0x00, 0xC7, 0x7B, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x29, 0xC4, 0x00, 0x00, 0xB4, 0xE1, 0x00, 0x00, 0x80, 0xE1, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0xB3, 0xDC, 0x00, 0x00, 0x5B, 0xDC, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0xDC, 0xDF, 0x00, 0x00, 0xEA, 0xFA, 0x00, 0x00, 0xA4, 0xFA, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x9C, 0xC1, 0x00, 0x00, 0x2D, 0xFC, 0x00, 0x00, 0x1D, 0xFC, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0x5F, 0x00, 0x00, 0xC8, 0x5F, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0xE3, 0xBD, 0x00, 0x00, 0xE4, 0xF5, 0x00, 0x00, 0xB3, 0xF5, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0D, 0x5A, 0x00, 0x00, 0x9F, 0x96, 0x00, 0x00, 0x8A, 0x96, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB1, 0x5E, 0x00, 0x00, 0x93, 0x5E, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2D, 0x9D, 0x00, 0x00, 0x16, 0xCC, 0x00, 0x00, 0xF3, 0xCB, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x35, 0xE5, 0x00, 0x00, 0x9C, 0xFD, 0x00, 0x00, 0x8F, 0xFD, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x95, 0xED, 0x00, 0x00, 0xBD, 0xFD, 0x00, 0x00, 0x9E, 0xFD, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4B, 0x62, 0x00, 0x00, 0xBF, 0x61, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0xE2, 0xB7, 0x00, 0x00, 0xEC, 0xD3, 0x00, 0x00, 0xB5, 0xD3, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xB3, 0xDC, 0x00, 0x00, 0x2F, 0xF7, 0x00, 0x00, 0xDC, 0xF6, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x4E, 0x9E, 0x00, 0x00, 0x71, 0xCF, 0x00, 0x00, 0x3D, 0xCF, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x20, 0xB7, 0x00, 0x00, 0xE6, 0xEC, 0x00, 0x00, 0xD4, 0xEC, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x5B, 0x00, 0x00, 0xB3, 0x5B, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x81, 0xCE, 0x00, 0x00, 0xB1, 0xF4, 0x00, 0x00, 0xAE, 0xF4, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x18, 0xE6, 0x00, 0x00, 0xAC, 0xFD, 0x00, 0x00, 0xA9, 0xFD, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x6D, 0x7E, 0x00, 0x00, 0x98, 0xD1, 0x00, 0x00, 0x95, 0xD1, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x99, 0x00, 0x00, 0x16, 0xC6, 0x00, 0x00, 0x13, 0xC6, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x50, 0xCB, 0x00, 0x00, 0xE0, 0xEA, 0x00, 0x00, 0xDD, 0xEA, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x86, 0xE9, 0x00, 0x00, 0x33, 0xFF, 0x00, 0x00, 0x30, 0xFF, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xB8, 0xDF, 0x00, 0x00, 0x61, 0xFB, 0x00, 0x00, 0x5C, 0xFB, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xFA, 0xEE, 0x00, 0x00, 0x4D, 0xFF, 0x00, 0x00, 0x4A, 0xFF, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x01, 0xA1, 0x00, 0x00, 0x40, 0xD3, 0x00, 0x00, 0x3C, 0xD3, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x35, 0x7E, 0x00, 0x00, 0x5F, 0xD1, 0x00, 0x00, 0x5A, 0xD1, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xA7, 0xE8, 0x00, 0x00, 0xAE, 0xFD, 0x00, 0x00, 0xAB, 0xFD, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xD0, 0xB1, 0x00, 0x00, 0x4F, 0xE7, 0x00, 0x00, 0x4C, 0xE7, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x7D, 0x00, 0x00, 0xBD, 0x7D, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xC7, 0x98, 0x00, 0x00, 0xD6, 0xC4, 0x00, 0x00, 0xD3, 0xC4, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0xD4, 0x93, 0x00, 0x00, 0xD3, 0xBC, 0x00, 0x00, 0xD0, 0xBC, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x21, 0xC5, 0x00, 0x00, 0x20, 0xE3, 0x00, 0x00, 0x0C, 0xE3, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x7F, 0x00, 0x00, 0xCE, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xB4, 0x00, 0x00, 0xF6, 0xE9, 0x00, 0x00, 0x4C, 0xE9, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0xA6, 0x69, 0x00, 0x00, 0x7C, 0xAA, 0x00, 0x00, 0xCB, 0xA9, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xF6, 0x98, 0x00, 0x00, 0x21, 0xC5, 0x00, 0x00, 0x7E, 0xC4, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x7C, 0xAA, 0x00, 0x00, 0xB8, 0xDF, 0x00, 0x00, 0xA7, 0xDF, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xCD, 0xB8, 0x00, 0x00, 0xFA, 0xEE, 0x00, 0x00, 0xB3, 0xEE, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x27, 0x5F, 0x00, 0x00, 0xA7, 0x9D, 0x00, 0x00, 0x1B, 0x9D, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x01, 0xD0, 0x00, 0x00, 0x30, 0xF1, 0x00, 0x00, 0x79, 0xF0, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0xB1, 0x5E, 0x00, 0x00, 0x2D, 0x9D, 0x00, 0x00, 0x00, 0x9D, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xD6, 0xC4, 0x00, 0x00, 0xA3, 0xE2, 0x00, 0x00, 0x17, 0xE2, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0xD7, 0x5E, 0x00, 0x00, 0x54, 0x9D, 0x00, 0x00, 0xC0, 0x9C, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x75, 0xA1, 0x00, 0x00, 0xCF, 0xD3, 0x00, 0x00, 0x4C, 0xD3, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0xE1, 0x7C, 0x00, 0x00, 0x87, 0xCF, 0x00, 0x00, 0x82, 0xCF, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6F, 0x72, 0x00, 0x00, 0xDA, 0xBA, 0x00, 0x00, 0xD7, 0xBA, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x40, 0x7C, 0x00, 0x00, 0x40, 0xCE, 0x00, 0x00, 0x3D, 0xCE, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xBE, 0xC9, 0x00, 0x00, 0x3E, 0xEE, 0x00, 0x00, 0x3B, 0xEE, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x10, 0x78, 0x00, 0x00, 0xE6, 0xC6, 0x00, 0x00, 0xE3, 0xC6, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x27, 0x77, 0x00, 0x00, 0xA7, 0xC4, 0x00, 0x00, 0xA4, 0xC4, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xAC, 0x72, 0x00, 0x00, 0x82, 0xBD, 0x00, 0x00, 0x7F, 0xBD, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xB8, 0x74, 0x00, 0x00, 0x78, 0xC0, 0x00, 0x00, 0x75, 0xC0, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x9F, 0x96, 0x00, 0x00, 0xDF, 0xC0, 0x00, 0x00, 0xDC, 0xC0, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x78, 0xC0, 0x00, 0x00, 0xF1, 0xF8, 0x00, 0x00, 0xEE, 0xF8, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0xFD, 0x68, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x71, 0x00, 0x00, 0x7D, 0x71, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x1C, 0x75, 0x00, 0x00, 0x9C, 0xC1, 0x00, 0x00, 0x99, 0xC1, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x74, 0x00, 0x00, 0x3D, 0x74, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7B, 0x00, 0x00, 0x7D, 0x7B, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x59, 0x00, 0x00, 0x7D, 0x59, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 0x72, 0x00, 0x00, 0xA9, 0x72, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x72, 0x00, 0x00, 0x13, 0x72, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xD2, 0xDC, 0x00, 0x00, 0x63, 0xFF, 0x00, 0x00, 0x60, 0xFF, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0x6D, 0x00, 0x00, 0xDC, 0x6D, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xFF, 0x75, 0x00, 0x00, 0x7E, 0xC3, 0x00, 0x00, 0x7B, 0xC3, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x5F, 0x00, 0x00, 0xBF, 0x5F, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x5C, 0x00, 0x00, 0xA1, 0x5C, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x5D, 0x00, 0x00, 0x92, 0x5D, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x5E, 0x00, 0x00, 0x71, 0x5E, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x7C, 0x00, 0x00, 0xDE, 0x7C, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x5A, 0x00, 0x00, 0x0A, 0x5A, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x96, 0x54, 0x00, 0x00, 0x17, 0x90, 0x00, 0x00, 0x14, 0x90, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x7A, 0x00, 0x00, 0xE4, 0x7A, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x7E, 0x77, 0x00, 0x00, 0xDD, 0xC5, 0x00, 0x00, 0xDA, 0xC5, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x49, 0xE4, 0x00, 0x00, 0xD1, 0xFF, 0x00, 0x00, 0xCE, 0xFF, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0xCD, 0xB8, 0x00, 0x00, 0xCA, 0xB8, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0xBE, 0xC8, 0x00, 0x00, 0xDB, 0xE7, 0x00, 0x00, 0xD8, 0xE7, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x94, 0x98, 0x00, 0x00, 0xF1, 0xC2, 0x00, 0x00, 0xEE, 0xC2, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0xC0, 0x7D, 0x00, 0x00, 0xC0, 0xD0, 0x00, 0x00, 0xBD, 0xD0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x92, 0xA9, 0x00, 0x00, 0xD2, 0xDC, 0x00, 0x00, 0xCF, 0xDC, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00 };
const FLOAT volumeLookup[11] = { 0.0, 0.013362, 0.032258, 0.058982, 0.096774, 0.150221, 0.225806, 0.3327, 0.483871, 0.697659, 1.0 };

// Make a byte from 2 ASCII bytes
int getByte(char msb, char lsb)
{
	int result = 0;
	char combo[2] = { msb, lsb };

	result = strtol(combo, NULL, 16);

	return result;
}

void SetMasterVolume(DWORD level)
{
	float volume = volumeLookup[level];
	info("OpenSndVoyager::SetMasterVolume level: %u volume: %f", level, volume);

	CHECK_HR(pMasterVoice->SetVolume(volume));
}

__declspec(dllexport) void snd_init_new(DWORD level)
{
	info("OpenSndVoyager::snd_init_new level: %u", level);

	bufferReady = FALSE;
	DWORD bytesRead = 0; // this is needed for windows 7

	char buf[MAX_PATH];
	memset(buf, 0, sizeof(buf));
	GetCurrentDirectoryA(256, buf);
	auto len = strlen(buf);
	buf[len] = '\\';
	strcat_s(buf, "stv\\arom\\");

	pDataBuffer = new BYTE[bufferSize];

	for (BYTE i = 0; i < 4; i++)
	{
		char filePath[MAX_PATH];
		sprintf_s(filePath, "%svoyager%u.bin", buf, i);
		info("OpenSndVoyager::snd_init_new loading %s", filePath);

		HANDLE hFile = CreateFileA((LPCSTR)filePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
		if (hFile == INVALID_HANDLE_VALUE)
		{
			info("OpenSndVoyager::snd_init_new ERROR! Opening file failed(%u)", GetLastError());
			return;
		}

		DWORD asdf = GetFileSize(hFile, NULL);


		if (asdf != binSize)
		{
			info("OpenSndVoyager::snd_init_new ERROR! Wrong file size! (%u)", asdf);
			return;
		}

		ReadFile(hFile, pDataBuffer + binSize * i, binSize, &bytesRead, NULL);
	}

	// Convert to unsigned
	for (size_t i = 0; i < bufferSize; i++)
	{
		pDataBuffer[i] = (BYTE)((char)pDataBuffer[i] + 128);
	}

	// Load hex file
	char filePath[MAX_PATH];
	sprintf_s(filePath, "%scpuarom.hex", buf);
	info("OpenSndVoyager::snd_init_new loading %s", filePath);
	HANDLE hFile = CreateFileA(filePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
	//HANDLE hFile = CreateFileA("D:\\Arcade\\Star Trek\\stv\\arom\\cpuarom.hex", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		info("ERROR! Opening file failed(%u)", GetLastError());
		return;
	}

	DWORD fileSize = GetFileSize(hFile, NULL);


	if (fileSize != hexSize)
	{
		info("ERROR! Wrong file size! (%u)", fileSize);
		return;
	}

	ReadFile(hFile, pHexBuffer, hexSize, &bytesRead, NULL);

	DWORD line = 0;
	BOOL done = FALSE;
	DWORD lineSize = 44;

	// Read per line
	while (done == FALSE)
	{
		DWORD lOffset = lineSize * line;
		BYTE start = pHexBuffer[lOffset + 0];
		BYTE count = getByte(pHexBuffer[lOffset + 1], pHexBuffer[lOffset + 2]);
		WORD address = getByte(pHexBuffer[lOffset + 3], pHexBuffer[lOffset + 4]) << 8 | getByte(pHexBuffer[lOffset + 5], pHexBuffer[lOffset + 6]);
		BYTE type = getByte(pHexBuffer[lOffset + 7], pHexBuffer[lOffset + 8]);

		//info("line: %d start: %X count: %X address: %04X type: %X data:", line, start, count, address, type);

		if (type == 0x01)
		{
			done = TRUE;
			continue;
		}

		if (start == 0x3A && count == 0x10 && address >= 0x00 && address <= sampleHeadersSize)
		{
			DWORD cursor = address;
			for (BYTE i = 9; i < 41; i += 2)
			{
				BYTE data = getByte(pHexBuffer[lOffset + i], pHexBuffer[lOffset + i + 1]);
				//printf(" %02X", data);
				pSampleHeaders[cursor] = data;
				cursor++;
			}
			//printf("\n");
		}
		else
		{
			// Error
			info("hex error");
			return;
		}

		line++;
	}

	// Init xAudio2
	CoInitialize(nullptr);
	CHECK_HR(XAudio2Create(&pXAudio2));
	CHECK_HR(pXAudio2->CreateMasteringVoice(&pMasterVoice));

	//CHECK_HR(pMasterVoice->SetVolume(0.5f));
	SetMasterVolume(level);

	// Init channel buffer
	for (BYTE channel = 0; channel < CHANNELS; channel++)
	{
		ResetChannel(channel);
	}

	bufferReady = TRUE;
}

__declspec(dllexport) void snd_code_always(INT code)
{
	info("OpenSndVoyager::snd_code_always code: %u", code);

}

void SetChannelVolume(BYTE channel, BYTE level)
{
	info("OpenSndVoyager::SetChannelVolume channel: %u level: %u", channel, level);

	if (channel >= CHANNELS) { return; }

	if (channelBuffer[channel].xaVoice == NULL) { return; }
	
	// TODO: do the proper level to volume conversion

	float fVolume = (float)level / 255.0f;
	CHECK_HR(channelBuffer[channel].xaVoice->SetVolume(fVolume));
}

void SetupChannel(BYTE channel)
{
	info("OpenSndVoyager::SetupChannel channel: %u", channel);

	if (channel >= CHANNELS) { return; }

	WORD sample = channelBuffer[channel].qSamples[0].sample;
	BYTE speed = channelBuffer[channel].qSamples[0].speed;
	BYTE level = channelBuffer[channel].qSamples[0].level;
	WORD stay = channelBuffer[channel].qSamples[0].stay;
	BOOL loop = channelBuffer[channel].loop;

	info("OpenSndVoyager::SetupChannel stay: %u", stay);

	DWORD base = 0;
	DWORD offsetBegin = 0;
	DWORD offsetEnd = 0;
	DWORD offsetOther = 0;
	DWORD size = 0;

	// Rest
	if (sample == 0xFFFF)
	{
		// Calculate how many bytes we need for ms rest
		WORD ms = (WORD)((float)level * restMultiplier);
		size = (DWORD)(SpeedToSampleRate(speed) * ms / 1000);
		level = 0;
		info("OpenSndVoyager::SetupChannel rest ms: %u size: %u", ms, size);
	}
	else
	{
		DWORD* pHeader = (DWORD*)blob + (sample * 4);

		base = pHeader[3] * 0x10000;
		offsetBegin = base + pHeader[0];
		offsetEnd = base + pHeader[1];
		offsetOther = base + pHeader[2];
		size = offsetEnd - offsetBegin;
	}

	info("OpenSndVoyager::SetupChannel channel: %X sample: %u speed: %X", channel, sample, speed);
	info("OpenSndVoyager::SetupChannel base: %X offsetBegin: %X offsetEnd: %X offsetOther: %X size: %X", base, offsetBegin, offsetEnd, offsetOther, size);

	// Setup new channel data
	auto sampleRate = SpeedToSampleRate(speed);
	auto sampleBits = 8;
	auto channels = 1;

	channelBuffer[channel].playing = TRUE;
	channelBuffer[channel].loop = loop;
	channelBuffer[channel].qIndex = 0;

	channelBuffer[channel].xaFormat.nAvgBytesPerSec = (sampleRate * sampleBits * channels) / 8;
	channelBuffer[channel].xaFormat.nSamplesPerSec = sampleRate;
	channelBuffer[channel].xaFormat.wBitsPerSample = sampleBits;
	channelBuffer[channel].xaFormat.nChannels = channels;
	channelBuffer[channel].xaFormat.wFormatTag = WAVE_FORMAT_PCM;
	channelBuffer[channel].xaFormat.nBlockAlign = (sampleBits * channels) / 8;

	channelBuffer[channel].xaBuffer.AudioBytes = bufferSize;
	channelBuffer[channel].xaBuffer.pAudioData = pDataBuffer;
	channelBuffer[channel].xaBuffer.Flags = XAUDIO2_END_OF_STREAM;
	channelBuffer[channel].xaBuffer.LoopBegin = 0;
	channelBuffer[channel].xaBuffer.LoopLength = 0;
	channelBuffer[channel].xaBuffer.LoopCount = 0;
	channelBuffer[channel].xaBuffer.PlayBegin = offsetBegin;
	channelBuffer[channel].xaBuffer.PlayLength = size;
	channelBuffer[channel].xaBuffer.pContext = NULL;

	if (loop)
	{
		channelBuffer[channel].xaBuffer.LoopBegin = channelBuffer[channel].xaBuffer.PlayBegin;
		channelBuffer[channel].xaBuffer.LoopLength = channelBuffer[channel].xaBuffer.PlayLength;
		channelBuffer[channel].xaBuffer.LoopCount = XAUDIO2_LOOP_INFINITE;
	}

	if (stay > 0)
	{
		float ms = (float)stay * restMultiplier;
		float length = (float)size / sampleRate * 1000;
		WORD lCount = (WORD)(ms / length);

		info("OpenSndVoyager::SetupChannel ms: %f length: %f lCount: %u", ms, length, lCount);

		if (lCount > 1)
		{
			channelBuffer[channel].xaBuffer.LoopBegin = channelBuffer[channel].xaBuffer.PlayBegin;
			channelBuffer[channel].xaBuffer.LoopLength = channelBuffer[channel].xaBuffer.PlayLength;
			channelBuffer[channel].xaBuffer.LoopCount = lCount;
		}
	}

	channelBuffer[channel].xaCallback.channel = channel;
	CHECK_HR(pXAudio2->CreateSourceVoice(&channelBuffer[channel].xaVoice, &channelBuffer[channel].xaFormat, 0, XAUDIO2_DEFAULT_FREQ_RATIO, &channelBuffer[channel].xaCallback));
	SetChannelVolume(channel, level);
	CHECK_HR(channelBuffer[channel].xaVoice->SubmitSourceBuffer(&channelBuffer[channel].xaBuffer));
	//CHECK_HR(channelBuffer[channel].xaVoice->Start(0));
}

DWORD SpeedToSampleRate(BYTE speed)
{
	info("OpenSndVoyager::SpeedToSampleRate speed: (0x%02X)", speed);

	DWORD sampleRate = 0;

	// This is pretty close but not 100% accurate!
	if (speed == 0x20 || speed == 0x25 || speed == 0x26)
	{
		sampleRate = 8000;
	}
	else if (speed == 0x30 || speed == 0x31 || speed == 0x32 || speed == 0x2A)
	{
		sampleRate = 11025;
	}
	else if (speed == 0x36)
	{
		sampleRate = 16000;
	}
	else if (speed == 0x40 || speed == 0x41 || speed == 0x3B)
	{
		sampleRate = 22050;
	}
	else if (speed == 0x60)
	{
		sampleRate = 96000;
	}
	else
	{
		info("OpenSndVoyager::SpeedToSampleRate unknown samplerate!! (0x%02X)", speed);
		sampleRate = 22050;
	}

	return sampleRate;
}

void PlayChannelNext(BYTE channel)
{
	info("OpenSndVoyager::PlayChannelNext channel: %u", channel);

	if (channel >= CHANNELS) { return; }

	channelBuffer[channel].qIndex++;

	WORD sample = channelBuffer[channel].qSamples[channelBuffer[channel].qIndex].sample;
	BYTE speed = channelBuffer[channel].qSamples[channelBuffer[channel].qIndex].speed;
	BYTE level = channelBuffer[channel].qSamples[channelBuffer[channel].qIndex].level;
	WORD stay = channelBuffer[channel].qSamples[channelBuffer[channel].qIndex].stay;

	info("OpenSndVoyager::SetupChannel stay: %u", stay);

	DWORD base = 0;
	DWORD offsetBegin = 0;
	DWORD offsetEnd = 0;
	DWORD offsetOther = 0;
	DWORD size = 0;

	// Rest
	if (sample == 0xFFFF)
	{
		// Calculate how many bytes we need for ms rest
		WORD ms = (WORD)((float)level * restMultiplier);
		size = (DWORD)(SpeedToSampleRate(speed) * ms / 1000);
		level = 0;
		info("OpenSndVoyager::PlayChannelNext rest ms: %u size: %u", ms, size);
	}
	else
	{
		DWORD* pHeader = (DWORD*)blob + (sample * 4);

		base = pHeader[3] * 0x10000;
		offsetBegin = base + pHeader[0];
		offsetEnd = base + pHeader[1];
		offsetOther = base + pHeader[2];
		size = offsetEnd - offsetBegin;
	}

	info("OpenSndVoyager::PlayChannelNext channel: %X sample: %u speed: %X", channel, sample, speed);
	info("OpenSndVoyager::PlayChannelNext base: %X offsetBegin: %X offsetEnd: %X offsetOther: %X size: %X", base, offsetBegin, offsetEnd, offsetOther, size);

	CHECK_HR(channelBuffer[channel].xaVoice->FlushSourceBuffers());

	// Setup new channel data
	auto sampleRate = SpeedToSampleRate(speed);
	auto sampleBits = 8;
	auto channels = 1;

	channelBuffer[channel].xaBuffer.AudioBytes = bufferSize;
	channelBuffer[channel].xaBuffer.pAudioData = pDataBuffer;
	channelBuffer[channel].xaBuffer.Flags = XAUDIO2_END_OF_STREAM;
	channelBuffer[channel].xaBuffer.LoopBegin = 0;
	channelBuffer[channel].xaBuffer.LoopLength = 0;
	channelBuffer[channel].xaBuffer.LoopCount = 0;
	channelBuffer[channel].xaBuffer.PlayBegin = offsetBegin;
	channelBuffer[channel].xaBuffer.PlayLength = size;
	channelBuffer[channel].xaBuffer.pContext = NULL;

	if (stay > 0)
	{
		float ms = (float)stay * restMultiplier;
		float length = (float)size / sampleRate * 1000;
		WORD lCount = (WORD)(ms / length);

		info("OpenSndVoyager::SetupChannel ms: %f length: %f lCount: %u", ms, length, lCount);

		if (lCount > 1)
		{
			channelBuffer[channel].xaBuffer.LoopBegin = channelBuffer[channel].xaBuffer.PlayBegin;
			channelBuffer[channel].xaBuffer.LoopLength = channelBuffer[channel].xaBuffer.PlayLength;
			channelBuffer[channel].xaBuffer.LoopCount = lCount;
		}
	}

	
	SetChannelVolume(channel, level);
	CHECK_HR(channelBuffer[channel].xaVoice->SubmitSourceBuffer(&channelBuffer[channel].xaBuffer));
	CHECK_HR(channelBuffer[channel].xaVoice->Start(0));
}

void PlayChannel(BYTE channel)
{
	if (channel >= CHANNELS) { return; }
	if (channelBuffer[channel].xaVoice == NULL) { return; }

	info("OpenSndVoyager::PlayChannel Playing channel %u", channel);

	CHECK_HR(channelBuffer[channel].xaVoice->Start(0));
	channelBuffer[channel].playing = TRUE;
}

void StopChannel(BYTE channel)
{
	if (channel >= CHANNELS) { return; }
	//if (!channelBuffer[channel].playing) { return; }
	//if (channelBuffer[channel].xaVoice == NULL) { return; }

	info("OpenSndVoyager::StopChannel Stopping channel %u", channel);
	if (channelBuffer[channel].playing && channelBuffer[channel].xaVoice != NULL)
	{
		CHECK_HR(channelBuffer[channel].xaVoice->Stop());
		channelBuffer[channel].playing = FALSE;
	}

	ResetChannel(channel);
}

void StopAllChannels()
{
	info("OpenSndVoyager::StopAllChannels");

	for (BYTE i = 0; i < CHANNELS; i++)
	{
		StopChannel(i);
	}
}

void ResetChannel(BYTE channel)
{
	info("ResetChannel %u", channel);

	if (channel >= CHANNELS) { return; }

	// Reset pointers
	if (channelBuffer[channel].xaVoice != NULL)
	{
		//CHECK_HR(channelBuffer[channel].xaVoice->FlushSourceBuffers()); // This causes race condition crash (aug 2020)
		channelBuffer[channel].xaVoice->DestroyVoice();
		channelBuffer[channel].xaVoice = NULL;
	}

	// Reset rest
	channelBuffer[channel].xaFormat = { 0 };
	channelBuffer[channel].xaBuffer = { 0 };
	//channelBuffer[channel].xaCallback = ? ;
	channelBuffer[channel].xaVoice = NULL;
	channelBuffer[channel].playing = FALSE;
	channelBuffer[channel].loop = FALSE;
	channelBuffer[channel].qSamples.clear();
	channelBuffer[channel].qIndex = -1;
}

void AddSampleToChannel(BYTE channel, WORD sample, BYTE speed, BYTE level)
{
	info("AddSampleToChannel channel: %u sample: %u speed: %u level: %u", channel, sample, speed, level);

	if (channel >= CHANNELS) { return; }

	channelBuffer[channel].qSamples.emplace_back(sample, speed, level, 0);
}

__declspec(dllexport) void sndPlay(INT code)
{
	if (!bufferReady) { info("OpenSndVoyager::sndPlay ERROR! Buffer not ready!"); return; }

	// Skip test menu sounds
	//if (code == 0x1b || code == 0x8b)
	//{
		//info("opensndvoyager::sndplay ignore test menu sounds!");
		//return;
	//}
	
	info("OpenSndVoyager::sndPlay code: %u", code);

	// Skip these for some reason
	if (code == -0x2a474b3 || code == 0xC2)
	{
		info("OpenSndVoyager::sndPlay Skip!");
		return;
	}

	// Master volume control
	if (code >= 1000 && code <= 1010)
	{
		SetMasterVolume(code - 1000);
		return;
	}

	// Kill all
	if (code == 0)
	{
		StopAllChannels();
		return;
	}

	// Final check
	//if (code > 499)
	//{
	//	info("OpenSndVoyager::sndPlay Invalid code!");
	//	return;
	//}

	// Mute music?
	if (MUTE_MUSIC && (code == 4 || code == 5 || code == 6 || code == 7 || code == 20 || code == 22 || code == 26 || code == 36 || code == 188 || code == 189 || code == 196 || code == 268 || code == 301))
	{
		return;
	}

	WORD hOffset = pSampleHeaders[code * 2] << 8 | pSampleHeaders[code * 2 + 1];
	BYTE* pSampleHeader = pSampleHeaders + hOffset;

	BYTE channel = pSampleHeader[0];
	BYTE unknown1 = pSampleHeader[1];
	BYTE unknown2 = pSampleHeader[2];
	BYTE level = 0xFF;
	WORD sample = 0;
	BYTE speed = 0x40;
	BOOL loop = FALSE;
	WORD qSize = 0;
	BOOL levelUsed = FALSE;

	// Nothing
	if (pSampleHeader[3] == OC_EOS || channel == 0x00)
	{
		info("OpenSndVoyager::sndPlay Nothing");
		return;
	}

	// Parse opcodes
	info("OpenSndVoyager::sndPlay parsing");
	ResetChannel(channel);

	BOOL parsing = TRUE;
	WORD cursor = 3;
	while (parsing)
	{
		switch (pSampleHeader[cursor])
		{
		case OC_REST:
			// Add delay (play silence for x ms)
			AddSampleToChannel(channel, 0xFFFF, speed, pSampleHeader[cursor + 1]);
			cursor += 2;
			break;
		case OC_START_VOICE:
			// Start parallel voice
			sndPlay(pSampleHeader[cursor + 1] + 0x200);
			cursor += 2;
			break;
		case OC_SETATTEN:
			// Volume
			level = pSampleHeader[cursor + 1];
			levelUsed = FALSE;
			cursor += 2;
			break;
		case OC_SETPATCH:
			// Found sample
			sample = pSampleHeader[cursor + 1] << 8 | pSampleHeader[cursor + 2];

			// Prevent false detections
			if (sample > 676)
			{
				cursor += 1;
				break;
			}

			// Some are shorter for some fucking reason
			if (pSampleHeader[cursor + 3] >= OC_SET_LUP_CNTL && pSampleHeader[cursor + 3] <= OC_DIAGNOSTIC)
			{
				cursor += 3;
			}
			else
			{
				speed = pSampleHeader[cursor + 3];
				cursor += 5;
			}
			
			AddSampleToChannel(channel, sample, speed, level);
			levelUsed = TRUE;
			break;
		case OC_SETPITCHOFFSET:
			// Skip this
			cursor += 3;
			break;
		case OC_STAY:
			// Add to last sample
			qSize = channelBuffer[channel].qSamples.size();

			if (qSize > 0)
				channelBuffer[channel].qSamples[qSize - 1].stay += pSampleHeader[cursor + 1];

			cursor += 2;
			break;
		case OC_SETENVELOPE:
			// Fuck this
			cursor += 2;
			break;
		case OC_STRING_BRANCH:
			//loop = TRUE;
			cursor += 3;
			break;
		case OC_SETPRIORITY:
			// Ignore
			cursor += 2;
			break;
		case OC_SYSKILLBSMT:
			// Kill channel i guess
			if (pSampleHeader[cursor + 1] != channel)
				StopChannel(pSampleHeader[cursor + 1]);
			cursor += 2;
			break;
		case OC_SEQSTARTVOICE:
			// Weird lookup opcode thing
			WORD temp;
			WORD realOpcode;

			temp = pSampleHeader[cursor + 2] << 8 | pSampleHeader[cursor + 3];
			realOpcode = *(pSampleHeaders + temp) + 0x200;
			info("OpenSndVoyager::sndPlay Sequenced realOpcode: %X", realOpcode);

			sndPlay(realOpcode);
			cursor += 4;
			break;
		case OC_CHANNELATTEN:
			// Ignore for now
			cursor += 2;
			break;
		case OC_SETMUSICTEMPO:
			// Ignore for now
			cursor += 2;
			break;
		case OC_LOCALTEMPO:
			// Ignore for now
			cursor += 2;
			break;
		case OC_SET_LUP_CNTL:
			// Ignore for now
			cursor += 2;
			break;
		case OC_SYSATTENDELTA:
			// Ignore for now
			// 1 Channel
			// 2 Delta
			cursor += 3;
			break;
		case OC_TEST_LUPC_JMP:
			// Ignore for now
			cursor += 2;
			break;
		case OC_SETGLOBALVAR:
			// Ignore for now
			cursor += 1;
			break;
		case OC_GETMUSICTEMPO:
			// Ignore for now
			cursor += 1;
			break;
		case OC_SETOCTOFF:
			// Ignore for now
			cursor += 2;
			break;
		case OC_SETNOTEOFF:
			// Ignore for now
			cursor += 2;
			break;
		case OC_SIGNEDATTEN:
			// Ignore for now
			// 1 channel
			// 2+3 relative volume
			cursor += 4;
			break;
		case OC_STRING_JSR:
			// Ignore for now
			cursor += 3;
			break;
		case OC_RANDOMDURATION:
			// Ignore for now
			cursor += 2;
			break;
		case OC_EOS:
			// Stop
			parsing = FALSE;
			break;
		default:
			// Dunno
			info("OpenSndVoyager::sndPlay Dunno OPCODE! code: %02X", pSampleHeader[cursor]);
			// opcode
			if (pSampleHeader[cursor] >= OC_SET_LUP_CNTL && pSampleHeader[cursor] <= OC_DIAGNOSTIC)
			{
				cursor += 1;
			}
			// not an opcode
			else
			{
				AddSampleToChannel(channel, sample, pSampleHeader[cursor], level);
				cursor += 2;
			}
			
			break;
		}
	}

	qSize = channelBuffer[channel].qSamples.size();

	if (qSize > 0)
	{
		if (!levelUsed)
			channelBuffer[channel].qSamples[qSize - 1].level += level;

		channelBuffer[channel].loop = loop;
		SetupChannel(channel);
		PlayChannel(channel);
	}
}